// Copyright (c) Microsoft Corporation. All rights reserved.

using System;
using System.Collections.Generic;
using System.Text;
using System.Globalization;

namespace Microsoft.TeamFoundation.Migration.Toolkit.Wit
{
    /// <summary>
    /// Base class for data associated with workitems such as links and file attachments.
    /// </summary>
    /// <typeparam name="T">Type of items being compared</typeparam>
    abstract class WorkItemAssociation<T> : IComparer<T>
    {
        private Pair<List<T>> m_unmatchedAssociations;

        /// <summary>
        /// Associations that do not have a match on the other side.
        /// </summary>
        public Pair<List<T>> Unmatched
        {
            get
            {
                return m_unmatchedAssociations;
            }
        }

        /// <summary>
        /// Indicates if the lists of associations are in sync.
        /// </summary>
        public bool InSync
        {
            get
            {
                return m_unmatchedAssociations.Left.Count == 0 && m_unmatchedAssociations.Right.Count == 0;
            }
        }

        /// <summary>
        /// Processes associations and detects possible conflicts
        /// </summary>
        /// <param name="associations">Associations</param>
        protected void Process(
            Pair<List<T>> associations)
        {
            associations.Left.Sort(this);
            associations.Right.Sort(this);

            CheckForDuplicates(associations);
            ParseLists(associations);
        }

        /// <summary>
        /// Check for duplicates within each side.  
        /// Throw an exception if there are duplicates.
        /// We cannot currently deal with a side having more than one attachment 
        /// with the same name and size.
        /// </summary>
        /// <param name="attachments">Attachments on both sides</param>
        protected virtual void CheckForDuplicates(Pair<List<T>> associations)
        {
            if (HasDuplicates(associations.Left))
            {
                // TODO: change message to more generic one (i.e. not "doc"
                throw new WitMigrationException(string.Format(CultureInfo.InvariantCulture,
                    Resources.DuplicateAssociationFound, "Left"));
            }

            if (HasDuplicates(associations.Right))
            {
                throw new WitMigrationException(string.Format(CultureInfo.InvariantCulture,
                    Resources.DuplicateAssociationFound, "Right"));
            }
        }

        /// <summary>
        /// Checks sorted list of associations for duplicates.
        /// </summary>
        /// <param name="list">List of associations</param>
        /// <returns>True if duplicates were found</returns>
        protected virtual bool HasDuplicates(
            List<T> list)
        {
            for (int i = 1; i < list.Count; i++)
            {
                if (Compare(list[i], list[i - 1]) == 0)
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// Populates lists indicating which sides of the pair the association exists on.
        /// </summary>
        private void ParseLists(Pair<List<T>> associations)
        {
            SymDiff<T> diff = new SymDiff<T>(
                associations.Left.ToArray(),
                associations.Right.ToArray(),
                this);

            m_unmatchedAssociations = new Pair<List<T>>(diff.LeftOnly, diff.RightOnly);
        }

        #region Comparison static method

        /// <summary>
        /// Compares the provided associated objects
        /// </summary>
        /// <param name="a1">The first object to compare</param>
        /// <param name="a2">The object to compare against</param>
        /// <returns>0 if the objects are equal, non-zero otherwise.</returns>
        public abstract int Compare(T a1, T a2);

        #endregion

    }
}
